
#include "block_queue.hpp"
#include "tesk.hpp"
#include<cstdio>

// template<class T>
// struct pthreaddata
// {
//     pthreaddata(std::string name, BlockQueue<T>* bq) : _name(name), _pbq(bq)
//     {
//     }
//     pthread_t _tid;
//     std::string _name;
//     BlockQueue<T> *_pbq;
// };

// pthread_mutex_t mutex; // 阻塞队列的互斥量

// pthread_cond_t pcond; // 生产者条件变量
// pthread_cond_t ccond; // 消费者条件变量

// BlockQueue<int> bq(&mutex, &pcond, &ccond);//创建一个阻塞队列

// void *producers_start(void *argc)
// {
//     BlockQueue<int> *bq = static_cast<BlockQueue<int> *>(argc);
//     while (true)
//     {
//         sleep(1);
//         int val = rand() % 10 + 1;
//         bq->Push(val);
//         std::cout << "producers->val: " << val << std::endl;
//     }
//     return nullptr;
// }

// void *consumer_start(void *argc)
// {
//     BlockQueue<int> *bq = static_cast<BlockQueue<int> *>(argc);
//     while (true)
//     {
//         int val;
//         bq->Pop(&val);
//         std::cout << "consumer->val: " << val << std::endl;
//     }
//     return nullptr;
// }

// int main()
// {
//     // 种下随机数种子
//     srand((unsigned int)time(nullptr) & 1223423);

//     pthread_t ptid1,ptid2, ptid3,ptid4;
//     pthread_t ctid1,ctid2,ctid3,ctid4;

//     BlockQueue<int> bq(&mutex, &pcond, &ccond);

//     // 生产者线程
//     pthread_create(&ptid1, nullptr, producers_start, &bq);
//     pthread_create(&ptid2, nullptr, producers_start, &bq);
//     pthread_create(&ptid3, nullptr, producers_start, &bq);
//     pthread_create(&ptid4, nullptr, producers_start, &bq);

//     // 消费者线程
//     pthread_create(&ctid1, nullptr, consumer_start, &bq);
//     pthread_create(&ctid2, nullptr, consumer_start, &bq);
//     pthread_create(&ctid3, nullptr, consumer_start, &bq);
//     pthread_create(&ctid4, nullptr, consumer_start, &bq);

//     // 等待线程/或者分离线程
//     pthread_join(ptid1, nullptr);
//     pthread_join(ptid2, nullptr);
//     pthread_join(ptid3, nullptr);
//     pthread_join(ptid4, nullptr);
//     pthread_join(ctid1, nullptr);
//     pthread_join(ctid2, nullptr);
//     pthread_join(ctid3, nullptr);
//     pthread_join(ctid4, nullptr);

//     return 0;
// }

// void *producers_start(void *argc)
// {
//     pthreaddata<int> *data = static_cast<pthreaddata<int> *>(argc);
//     while (true)
//     {
//         //sleep(1);
//         int val = rand() % 10 + 1;
//         data->_pbq->Push(val);
//         std::cout << data->_name << "   producers->val: " << val << std::endl;
//     }
//     return nullptr;
// }

// void *consumer_start(void *argc)
// {
//     pthreaddata<int> *data = static_cast<pthreaddata<int> *>(argc);
//     while (true)
//     {
//         sleep(1);
//         int val;
//         data->_pbq->Pop(&val);
//         std::cout << data->_name << "    consumer->val: " << val << std::endl;
//     }
//     return nullptr;
// }

// int main()
// {

//     std::vector<pthreaddata<int> *> pvect;
//     std::vector<pthreaddata<int> *> cvect;

//     for (int i = 0; i < 3; i++)
//     {
//         std::string name = "producers pthrea->";
//         name += std::to_string(i + 1);
//         pthreaddata<int> *tmp = new pthreaddata<int>(name, &bq);
//         pthread_create(&(tmp->_tid), nullptr, producers_start, tmp);
//         pvect.push_back(tmp);
//     }

//     for (int i = 0; i < 4; i++)
//     {
//         std::string name = "consumer  pthrea->";
//         name += std::to_string(i + 1);
//         pthreaddata<int> *tmp = new pthreaddata<int>(name, &bq);
//         pthread_create(&(tmp->_tid), nullptr, consumer_start, tmp);
//         cvect.push_back(tmp);
//     }

//     for (int i = 0; i < 3; i++)
//     {
//         pthread_join((pvect[i]->_tid), nullptr);
//     }

//     for (int i = 0; i < 4; i++)
//     {
//         pthread_join((cvect[i]->_tid), nullptr);
//     }

//     while(1);

//     return 0;
// }

// void *consumer(void *argc)
// {
//     while (true)
//     {
//         sleep(1);
//         BlockQueue<int> *bq = static_cast<BlockQueue<int> *>(argc);
//         int val;
//         bq->pop(&val);
//         std::cout << "消费数据: " << val << std::endl;
//     }

//     return nullptr;
// }
// void *producers(void *argc)
// {
//     while (true)
//     {
//         //sleep(1);
//         BlockQueue<int> *bq = static_cast<BlockQueue<int> *>(argc);
//         int val = rand() % 9 + 1;
//         bq->push(val);
//         std::cout << "生产数据: " << val << std::endl;

//     }

//     return nullptr;
// }

// int main()
// {
//     srand((unsigned int)time(nullptr) & 324232);
//     // 创建阻塞队列
//     BlockQueue<int> *bq = new BlockQueue<int>(10);

//     pthread_t c, p;

//     pthread_create(&p, nullptr, producers, bq);
//     pthread_create(&c, nullptr, consumer, bq);

//     pthread_join(c, nullptr);
//     pthread_join(p, nullptr);
//     delete bq;

//     return 0;
// }

int myadd(int x, int y)
{
    return x + y;
}

int countfun(int x, int y, char op)
{
    int ret = 0;
    switch (op)
    {
    case '+':
        ret = x + y;
        break;
    case '-':
        ret = x - y;
        break;
    case '*':
        ret = x * y;
        break;
    case '/':
        if (y == 0)
        {
            std::cout << "error" << std::endl;
            return -1;
        }
        ret = x / y;
        break;
    case '%':
        if (y == 0)
        {
            std::cout << "error" << std::endl;
            return -1;
        }
        ret = x % y;
        break;
    default:
        std::cout << "error" << std::endl;
        break;
    }
    return ret;
}

void storagefun(const std::string str)
{
    FILE* fd = fopen("./test.txt","a+");
    if(fd == nullptr)
    {
        std::cout<< "fopen error"<<std::endl;
        return ;
    }
    
    //fwrite(str.c_str(), str.size(), 1, fd);
    
    fputs(str.c_str(), fd);
    fputc('\n', fd);


    fclose(fd);
    
}


struct data
{
    data(BlockQueue<Count_Tesk> *bq1, BlockQueue<Storage_Tesk> *bq2)
        : _bq1(bq1), _bq2(bq2)
    {
    }
    BlockQueue<Count_Tesk> *_bq1;
    BlockQueue<Storage_Tesk> *_bq2;
};

void *consumer(void *argc)
{
    while (true)
    {
        // sleep(1);
        data *bq12 = static_cast<data *>(argc);
        Count_Tesk t1;
        // 消费者从bq1里面取数据，
        bq12->_bq1->pop(&t1);
        // 存放在bq2中
        char buf[128];
        snprintf(buf, 128, "%d %c %d = %d", t1._x, t1._op, t1._y, t1());
        std::cout << "消费任务：" << buf << std::endl;
        Storage_Tesk t2(buf,storagefun);
        bq12->_bq2->push(t2);
        std::cout << "写入完成。。。。"<<std::endl;
    }

    return nullptr;
}

void *producers(void *argc)
{
    while (true)
    {
        
        BlockQueue<Count_Tesk> *bq1 = static_cast<BlockQueue<Count_Tesk> *>(argc);
        int x = rand() % 9 + 1;
        int y = rand() % 9;
        char ops[5] = {'+', '-', '*', '/', '%'};
        // Tesk t(x,y, myadd);
        Count_Tesk t(x, y, ops[rand() % 5], countfun);
        //sleep(1);
        bq1->push(t);
        std::cout << "生产任务: " << x << " " << t._op << " " << y << " = ?" << std::endl;
    }

    return nullptr;
}

void *storage(void *argc)
{
    BlockQueue<Storage_Tesk> *bq2 = static_cast<BlockQueue<Storage_Tesk> *>(argc);
    while (true)
    {
        Storage_Tesk t;
        bq2->pop(&t);
        t();
        std::cout << "存储任务完成。。。。"<<std::endl;
    }
}



int main()
{
    srand((unsigned int)time(nullptr) & 324232);
    // 创建阻塞队列
    BlockQueue<Count_Tesk> *bq1 = new BlockQueue<Count_Tesk>(10);
    BlockQueue<Storage_Tesk> *bq2 = new BlockQueue<Storage_Tesk>(10);
    data *bq12 = new data(bq1, bq2);

    pthread_t c, p, s;
    pthread_t c1, p1, s1;
    pthread_t c2, p2, s2;
    //这里的代码可以直接改为多生产多消费的模型。
    //因为阻塞队列只有一个，只有一个线程可以进入阻塞队列中。
    pthread_create(&p, nullptr, producers, bq1);
    pthread_create(&p1, nullptr, producers, bq1);
    pthread_create(&p2, nullptr, producers, bq1);


    pthread_create(&c, nullptr, consumer, bq12);
    pthread_create(&c1, nullptr, consumer, bq12);
    pthread_create(&c2, nullptr, consumer, bq12);
    pthread_create(&s, nullptr, storage, bq2);
    pthread_create(&s1, nullptr, storage, bq2);
    pthread_create(&s2, nullptr, storage, bq2);

    pthread_join(c, nullptr);
    pthread_join(c1, nullptr);
    pthread_join(c2, nullptr);
    pthread_join(p, nullptr);
    pthread_join(p1, nullptr);
    pthread_join(p2, nullptr);
    pthread_join(s, nullptr);
    pthread_join(s1, nullptr);
    pthread_join(s2, nullptr);
    
    delete bq2;
    delete bq1;
    delete bq12;

    return 0;
}


//这里的高效体现在什么地方 ，把产品放入队列之前，和把产品从队列中取出之后的处理过程是 并发的。
